#ifndef __MFL_H__
#define __MFL_H__

#include "common.h"
#include <stdbool.h>

typedef struct {
  float32 X1;
  float32 Y1;
} Mfl_StatePT1_Type;
typedef struct {
  float32 X1;
  float32 X2;
  float32 Y1;
} Mfl_StateDT1Typ1_Type;
typedef struct {
  float32 X1;
  float32 Y1;
} Mfl_StateDT1Typ2_Type;
typedef struct {
  float32 X1;
  float32 Y1;
} Mfl_StatePD_Type;
typedef struct {
  float32 K_C;
  float32 Tv_C;
} Mfl_ParamPD_Type;
typedef struct {
  float32 X1;
  float32 Y1;
} Mfl_StateI_Type;
typedef struct {
  float32 X1;
  float32 Y1;
} Mfl_StatePI_Type;
typedef struct {
  float32 K_C;
  float32 Tnrec_C;
} Mfl_ParamPI_Type;
typedef struct {
  float32 X1;
  float32 X2;
  float32 Y1;
} Mfl_StatePID_Type;
typedef struct {
  float32 K_C;
  float32 Tv_C;
  float32 Tnrec_C;
} Mfl_ParamPID_Type;
typedef struct {
  float32 Min_C;
  float32 Max_C;
} Mfl_Limits_Type;
typedef struct {
  float32 SlopePos_f32;
  float32 SlopeNeg_f32;
} Mfl_ParamRamp_Type;
typedef struct {
  float32 State_f32;
  sint8 Dir_s8;
  sint8 Switch_s8;
} Mfl_StateRamp_Type;
typedef struct {
  float32 dsintStatic;
  float32 *lszStatic;
  float32 *dtbufBegStatic;
  float32 *dtbufEndStatic;
} Mfl_DeadTimeParam_Type;
typedef struct {
  float32 TimeHighLow;
  float32 TimeLowHigh;
} Mfl_DebounceParam_Type;
typedef struct {
  boolean XOld;
  float32 Timer;
} Mfl_DebounceState_Type;

typedef enum { E_SUCCESS = 0U, E_DIVBYZERO = 1U, E_INVALID = 2U } Mfl_Status;
typedef struct {
  Mfl_Status status;
} Mfl_Mod_St_Type;
typedef struct {
  Mfl_Status status;
} Mfl_Div_St;

// Floating point to Fixed-Point Conversion
uint16 Mfl_Cvrt_f32_u16(float32 value, sint16 exp); // 0x01
sint16 Mfl_Cvrt_f32_s16(float32 value, sint16 exp); // 0x02
uint32 Mfl_Cvrt_f32_u32(float32 value, sint16 exp); // 0x03
sint32 Mfl_Cvrt_f32_s32(float32 value, sint16 exp); // 0x04

// Fixed-Point to Floating-Point Conversion
float32 Mfl_Cvrt_u16_f32(uint16 value, sint16 exp); // 0x05
float32 Mfl_Cvrt_s16_f32(sint16 value, sint16 exp); // 0x06
float32 Mfl_Cvrt_u32_f32(uint32 value, sint16 exp); // 0x07
float32 Mfl_Cvrt_s32_f32(sint32 value, sint16 exp); // 0x08

// Rounding
float32 Mfl_Trunc_f32(float32 ValValue);
float32 Mfl_Round_f32(float32 ValValue);
float32 Mfl_Ceil_f32(float32 ValValue);
float32 Mfl_Floor_f32(float32 ValValue);

// Proportional Controller
void Mfl_PCalc(float32 X_f32, float32 *P_pf32, float32 K_f32);
float32 Mfl_POut_f32(const float32 *P_pf32);

// Proportional controller with first order time constant
void Mfl_PT1Calc(float32 X_f32, Mfl_StatePT1_Type *State_cpst, float32 K_f32,
                 float32 TeQ_f32);
void Mfl_PT1SetState(Mfl_StatePT1_Type *State_cpst, float32 X1_f32,
                     float32 Y1_f32);
float32 Mfl_CalcTeQ_f32(float32 T1rec_f32, float32 dT_f32);
float32 Mfl_CalcTeQApp_f32(float32 T1rec_f32, float32 dT_f32);
float32 Mfl_PT1Out_f32(const Mfl_StatePT1_Type *State_cpst);

// Differential component with time delay : DT1
void Mfl_DT1Typ1Calc(float32 X_f32, Mfl_StateDT1Typ1_Type *State_cpst,
                     float32 K_f32, float32 TeQ_f32, float32 dT_f32);
void Mfl_DT1Typ2Calc(float32 X_f32, Mfl_StateDT1Typ2_Type *State_cpst,
                     float32 K_f32, float32 TeQ_f32, float32 dT_f32);
void Mfl_DT1Typ1SetState(Mfl_StateDT1Typ1_Type *State_cpst, float32 X1_f32,
                         float32 X2_f32, float32 Y1_f32);
void Mfl_DT1Typ2SetState(Mfl_StateDT1Typ2_Type *State_cpst, float32 X1_f32,
                         float32 Y1_f32);
float32 Mfl_DT1Typ1Out_f32(const Mfl_StateDT1Typ1_Type *State_cpst);
float32 Mfl_DT1Typ2Out_f32(const Mfl_StateDT1Typ2_Type *State_cpst);

// Proportional & Differential controller
void Mfl_PDCalc(float32 X_f32, Mfl_StatePD_Type *State_cpst,
                const Mfl_ParamPD_Type *Param_cpst, float32 dT_f32);
void Mfl_PDSetState(Mfl_StatePD_Type *State_cpst, float32 X1_f32,
                    float32 Y1_f32);
void Mfl_PDSetParam(Mfl_ParamPD_Type *Param_cpst, float32 K_f32,
                    float32 Tv_f32);
float32 Mfl_PDOut_f32(const Mfl_StatePD_Type *State_cpst);

// Integral component
void Mfl_ICalc(float32 X_f32, Mfl_StateI_Type *State_cpst, float32 K_f32,
               float32 dT_f32);
void Mfl_ILimCalc(float32 X_f32, Mfl_StateI_Type *State_cpst, float32 K_f32,
                  const Mfl_Limits_Type *Limit_cpst, float32 dT_f32);
void Mfl_CtrlSetLimit(float32 Min_f32, float32 Max_f32,
                      Mfl_Limits_Type *Limit_cpst);
void Mfl_CtrlSetLimits(Mfl_Limits_Type *Limit_cpst, float32 Min_f32,
                       float32 Max_f32);
void Mfl_ISetState(Mfl_StateI_Type *State_cpst, float32 X1_f32, float32 Y1_f32);
float32 Mfl_IOut_f32(const Mfl_StateI_Type *State_cpst);

// Proportional & Integral controller
void Mfl_PITyp1Calc(float32 X_f32, Mfl_StatePI_Type *State_cpst,
                    const Mfl_ParamPI_Type *Param_cpst, float32 dT_f32);
void Mfl_PITyp1LimCalc(float32 X_f32, Mfl_StatePI_Type *State_cpst,
                       const Mfl_ParamPI_Type *Param_cpst,
                       const Mfl_Limits_Type *Limit_cpst, float32 dT_f32);
void Mfl_PITyp2Calc(float32 X_f32, Mfl_StatePI_Type *State_cpst,
                    const Mfl_ParamPI_Type *Param_cpst, float32 dT_f32);
void Mfl_PITyp2LimCalc(float32 X_f32, Mfl_StatePI_Type *State_cpst,
                       const Mfl_ParamPI_Type *Param_cpst,
                       const Mfl_Limits_Type *Limit_cpst, float32 dT_f32);
void Mfl_PISetState(Mfl_StatePI_Type *State_cpst, float32 X1_f32,
                    float32 Y1_f32);
void Mfl_PISetParam(Mfl_ParamPI_Type *Param_cpst, float32 K_f32,
                    float32 Tnrec_f32);
float32 Mfl_PIOut_f32(const Mfl_StatePI_Type *State_cpst);

// Proportional, Integral & Differential controller
void Mfl_PIDTyp1Calc(float32 X_f32, Mfl_StatePID_Type *State_cpst,
                     const Mfl_ParamPID_Type *Param_cpst, float32 dT_f32);
void Mfl_PIDTyp1LimCalc(float32 X_f32, Mfl_StatePID_Type *State_cpst,
                        const Mfl_ParamPID_Type *Param_cpst,
                        const Mfl_Limits_Type *Limit_cpst, float32 dT_f32);
void Mfl_PIDTyp2Calc(float32 X_f32, Mfl_StatePID_Type *State_cpst,
                     const Mfl_ParamPID_Type *Param_cpst, float32 dT_f32);
void Mfl_PIDTyp2LimCalc(float32 X_f32, Mfl_StatePID_Type *State_cpst,
                        const Mfl_ParamPID_Type *Param_cpst,
                        const Mfl_Limits_Type *Limit_cpst, float32 dT_f32);
void Mfl_PIDSetState(Mfl_StatePID_Type *State_cpst, float32 X1_f32,
                     float32 X2_f32, float32 Y1_f32);
void Mfl_PIDSetParam(Mfl_ParamPID_Type *Param_cpst, float32 K_f32,
                     float32 Tv_f32, float32 Tnrec_f32);
float32 Mfl_PIDOut_f32(const Mfl_StatePID_Type *State_cpst);

// Magnitude and Sign
float32 Mfl_Abs_f32(float32 ValValue);
sint8 Mfl_Sign_f32(float32 ValValue);

// Limiting
float32 Mfl_Max_f32(float32 ValValue1, float32 ValValue2);
float32 Mfl_Min_f32(float32 Value1, float32 Value2);
float32 Mfl_RateLimiter_f32(float32 newval, float32 oldval, float32 maxdif);
float32 Mfl_Limit_f32(float32 val, float32 lowLim, float32 upLim);

// Logarithms and Exponentials
float32 Mfl_Pow_f32(float32 ValBase, float32 ValExp);
float32 Mfl_Sqrt_f32(float32 ValValue);
float32 Mfl_Exp_f32(float32 ValValue);
float32 Mfl_Log_f32(float32 ValValue);

// Trigonometry
float32 Mfl_Sin_f32(float32 value);
float32 Mfl_Cos_f32(float32 value);
float32 Mfl_Tan_f32(float32 value);
float32 Mfl_arcSin_f32(float32 value);
float32 Mfl_ArcSin_f32(float32 value);
float32 Mfl_arcCos_f32(float32 value);
float32 Mfl_ArcCos_f32(float32 value);
float32 Mfl_arcTan_f32(float32 value);
float32 Mfl_ArcTan_f32(float32 value);
float32 Mfl_arcTan2_f32(float32 X1_f32, float32 X2_f32);
float32 Mfl_ArcTan2_f32(float32 X1_f32, float32 X2_f32);

// Average
float32 Mfl_Average_f32_f32(float32 value1, float32 value2);

// Array Average
float32 Mfl_ArrayAverage_f32_f32(const float32 *Array, uint32 Count);

// Hypotenuse
float32 Mfl_Hypot_f32f32_f32(float32 x_value, float32 y_value);

// Ramp routines
void Mfl_RampCalc(float32 X_f32, Mfl_StateRamp_Type *State_cpst,
                  const Mfl_ParamRamp_Type *Param_cpcst, float32 dT_f32);
void Mfl_RampInitState(Mfl_StateRamp_Type *State_cpst, float32 Val_f32);
void Mfl_RampSetParam(Mfl_ParamRamp_Type *Param_cpst, float32 SlopePosVal_f32,
                      float32 SlopeNegVal_f32);
float32 Mfl_RampOut_f32(const Mfl_StateRamp_Type *State_cpcst);
void Mfl_RampCalcJump(float32 X_f32, Mfl_StateRamp_Type *State_cpst);
float32 Mfl_RampCalcSwitch_f32(float32 Xa_f32, float32 Xb_f32,
                               Mfl_StateRamp_Type *State_cpst,
                               const Mfl_ParamRamp_Type *Param_cpcst,
                               float32 dT_f32);
float32 Mfl_RampCalcSwitch(float32 Xa_f32, float32 Xb_f32, boolean Switch,
                           Mfl_StateRamp_Type *State_cpst);
boolean Mfl_RampGetSwitchPos(const Mfl_StateRamp_Type *State_cpst);
boolean Mfl_RampCheckActivity(const Mfl_StateRamp_Type *State_cpst);

// Hysteresis routines
boolean Mfl_HystCenterHalfDelta_f32_u8(float32 X, float32 center,
                                       float32 halfDelta, uint8 *State);
boolean Mfl_HystLeftRight_f32_u8(float32 X, float32 Lsp, float32 Rsp,
                                 uint8 *State);
boolean Mfl_HystDeltaRight_f32_u8(float32 X, float32 Delta, float32 Rsp,
                                  const uint8 *State);
boolean Mfl_HystLeftDelta_f32_u8(float32 X, float32 Lsp, float32 Delta,
                                 uint8 *State);

// Mfl_DeadTime
float32 Mfl_DeadTime_f32_f32(float32 X, float32 DelayTime, float32 StepTime,
                             Mfl_DeadTimeParam_Type *Param);

// Debounce routines
boolean Mfl_Debounce_u8_u8(boolean X, Mfl_DebounceState_Type *State,
                           const Mfl_DebounceParam_Type *Param, float32 dT);
void Mfl_DebounceInit(Mfl_DebounceState_Type *State, boolean X);

void Mfl_DebounceSetparam(Mfl_DebounceParam_Type *Param, float32 THighLow,
                          float32 TLowHigh);
void Mfl_DebounceSetParam(Mfl_DebounceParam_Type *Param, float32 THighLow,
                          float32 TLowHigh);

// Ascending Sort Routine
void Mfl_SortAscend_f32(float32 *Array, uint16 Num);

// Descending Sort Routine
void Mfl_SortDescend_f32(float32 *Array, uint16 Num);

// Median sort routine
float32 Mfl_MedianSort_f32_f32(float32 *Array, uint8 N);

float32 Mfl_IntToFloatCvrt_u8_f32(uint8 ValInteger);
float32 Mfl_IntToFloatCvrt_s8_f32(sint8 ValInteger);
float32 Mfl_IntToFloatCvrt_u16_f32(uint16 ValInteger);
float32 Mfl_IntToFloatCvrt_s16_f32(sint16 ValInteger);
float32 Mfl_IntToFloatCvrt_u32_f32(uint32 ValInteger);
float32 Mfl_IntToFloatCvrt_s32_f32(sint32 ValInteger);
// float32 Mfl_IntToFloatCvrt_u64_f32(uint64 ValInteger);
// float32 Mfl_IntToFloatCvrt_s64_f32(sint64 ValInteger);

uint8 Mfl_FloatToIntCvrt_f32_u8(float32 ValFloat);
sint8 Mfl_FloatToIntCvrt_f32_s8(float32 ValFloat);
uint16 Mfl_FloatToIntCvrt_f32_u16(float32 ValFloat);
sint16 Mfl_FloatToIntCvrt_f32_s16(float32 ValFloat);
uint32 Mfl_FloatToIntCvrt_f32_u32(float32 ValFloat);
sint32 Mfl_FloatToIntCvrt_f32_s32(float32 ValFloat);

#endif